<style scoped>
.form-br{height: 10px;width: 100%;background: var(--color-bg);}
</style>
<template>
  <form @submit.prevent="onsubmit">
    <template v-for="(row,k) in config" >
      <template v-if="!row.remove">
        <input v-if="row.type==='hidden'" type="hidden" :name="row.name" :value="row.value" />
        <div v-else-if="row.type==='br'" class="form-br"></div>
        <template v-else-if="$slots[row.type]">
          <slot :name="row.type" :row="row" :value="row.value"></slot>
        </template>
        <component v-else-if="is_component(row.type)"
                   required v-bind="row.bind_param" :is="row.type" v-model="row.value" @change="onchange(row, $event)"></component>
        <text_one v-else v-bind="row.bind_param" v-model="row.value" @change="onchange(row, $event)"></text_one>
        <div v-if="row.type!=='br'&&row.br" class="form-br"></div>
      </template>
    </template>
    <van-cell v-if="$slots['submit']">
      <template #value>
        <slot name="submit"></slot>
      </template>
    </van-cell>
  </form>
</template>

<script>
import s94 from 's94-js'
import text_one from "@/components/form_field/text_one.vue"
import text_more from "@/components/form_field/text_more.vue"
import select_one from "./form_field/select_one.vue"
import radio from "./form_field/radio.vue"
import checkbox from "./form_field/checkbox.vue"
import radio_switch from "./form_field/radio_switch.vue"
import select_address from "./form_field/select_address.vue"
import file from "./form_field/file.vue"
import file_img from "./form_field/file_img.vue"
import file_imgs from "./form_field/file_imgs.vue"
import date from "./form_field/date.vue"
import sku from "@/components/form_field/sku.vue"
import editor from "@/components/form_field/editor.vue"

export default {
  name: "form_param",
  components: {text_one, text_more, select_one, radio, checkbox, radio_switch, select_address, file, file_img, file_imgs, date, sku, editor},
  props: {
    config: [Array, Object],
    submit: Function,
    remove_name: Boolean,
    readonly: Boolean,
  },
  emits: ["change","submit"],
  data(){
    this.display();
    return {
      error_map: {},
      value: "",
      init_value_json: '',
    }
  },
  methods: {
    display(){
      // 格式化 config 每一项
      Object.values(this.config).forEach(row=>{
        let bind_param = Object.assign({}, row);
        //name
        if (this.remove_name) bind_param.name = '';
        if (bind_param.name && ~bind_param.name.indexOf('.')){
          let arr = bind_param.name.split('.');
          bind_param.name = '';
          arr.forEach((v,i)=>{
            bind_param.name += i>0 ? `[${v}]` : v;
          })
        }
        // 是否只读
        bind_param.is_info = !!this.is_info(bind_param);
        // placeholder
        if (bind_param.tips) bind_param.placeholder = bind_param.tips;
        if (!bind_param.placeholder) {
          if (~['text_more','text_one'].indexOf(bind_param.type)) {
            bind_param.placeholder = '请输入'+bind_param.label
          }
          if (~['select_one','date'].indexOf(bind_param.type)) {
            bind_param.placeholder = '请选择'+bind_param.label
          }
        }
        if (bind_param.is_info) bind_param.placeholder = '';
        //align
        let def_label_align = '';
        if (~['text_more','select_address'].indexOf(row.type)) def_label_align='top';
        bind_param['label-align'] = row.label_align || def_label_align;
        let def_align = 'left';
        if (bind_param.is_info && !row.align && bind_param['label-align']!=='top') def_align = 'right';
        if (~['radio_switch','select_one','date','sku'].indexOf(row.type)) def_align = 'right';
        bind_param['input-align'] = row.align || def_align;

        delete bind_param['type'];
        delete bind_param['value'];

        row.bind_param = bind_param;
      })
    },
    is_info(row){
      return this.readonly || row.is_info || (typeof row.can_edit !== 'undefined' && !row.can_edit);
    },
    is_component(type){
      return !!~Object.keys(this.$options.components).indexOf(type);
    },
    onchange(row, v){
      this.$emit('change',row, v, this.config);
      if (typeof(row.onchange) == 'function') row.onchange(row, v);
    },
    click_link(e, row){
      let input_dom = e.target.querySelector('.input-outer>*');
      if (!input_dom) return;
      let is_link = !!~['select_one','date'].indexOf(row.type);
      if (!is_link) return;
      input_dom.click();
    },
    form_data(){
      return Object.values(this.config).reduce((res,row)=>{
        if (row.name) res[row.name] = row.value;
        return res;
      },{});
    },
    onsubmit(){
      let data = new FormData(this.$el);
      if (!this.submit) return;
      Promise.resolve(this.submit(data)).catch((error_map)=>{
        this.error(error_map);
      })
    },
    error(error_map){
      if(typeof error_map !== 'object') return;
      Object.keys(error_map).forEach(k=>{
        error_map[k] = s94.to_string(error_map[k]);
      })
      this.error_map = error_map;
    },
    init(init_value){
      this.errors = {};
      let value_arr = JSON.parse(this.init_value_json);
      if (typeof(init_value)=='object') {
        Object.assign(value_arr, init_value);
        this.init_value_json = JSON.stringify(value_arr);
      }
      Object.values(this.config).forEach(row=>{
        if (row.name && typeof(value_arr[row.name])!='undefined') row.value = value_arr[row.name];
      })
    },
    set_init_value(){
      let init_value = Object.values(this.config).reduce((res,row)=>{
        if (row.name) res[row.name] = typeof(row.value)=='undefined' ? '' : row.value;
        return res;
      },{});
      this.init_value_json = JSON.stringify(init_value);
    },
  },
  watch:{
    config(){
      this.display();
    },
  },
  mounted() {
    this.set_init_value();
  }
}
</script>